/* Filename:    nhodChat.c
 * Author:      John Van Drasek
 * Date:        28 December 2006
 * Description: Source file for chat server functionality
 */


//////////////
// Includes //
//////////////

// User defined includes
#include "nhodChat.h"
#include "pthread.h"

pthread_t tChatServer;
int chatSock;
//////////////////////////
// Function definitions //
//////////////////////////

/* startChatServer
*
*  Description: Start the chat server by creating the thread to
*                execute the chatServer function.
*
*  Input: NA
*  Output: NA
*/
void startChatServer()
{

	int threadID;
	int ret;

	threadID = 2;

	ret = pthread_create(&tChatServer, NULL, chatServer, (void*)threadID);
	ret = pthread_detach(tChatServer);
}


/* stopChatServer
*
*  Description: Stop the chat server by canceling the thread
*                running hte chatServer function.
*
*  Input: NA
*  Output: NA
*/
void stopChatServer()
{
	if(!(pthread_cancel(tChatServer)))
	{
		printf("Chat server was stopped successfully!\n");
		rup_close(chatSock);//??? we need to close sock here cause we kill the for loop in chatServer() and it doesn't get done???
	}
	else
	{
		printf("Something went wrong while trying to stop chat server!  :(\n");
	}
}


/* sendChatToList
*
*  Description: Send the chat to the list of IP Addresses being managed by
*                the login server.
*
*  Input: int in_sock - A valid RUP file descriptor.
*  Input: struct sockaddr_in* from - A socket address structure containing
*          the remote ip address and port number.
*  Input: char* sentFromClientName - A pointer to the string containing the
*          name of the client who sent the chat.
*  Input: char* chatData - A pointer to the string containing the chat data
*          to be sent to the server.
*  Output: NA
*/
void sendChatToList(int in_sock, struct sockaddr_in* from, char* sentFromClientName, char* chatData, int in_pktId)
{
	chatSock = in_sock;
	int sharedListNumber;
	int curListNumber;
	int curListSize;
	struct sockaddr_in client;
	struct pkt* myPkt;
	struct pktNode* curPktNode;

	// Set the shared number to zero(zero is the first index in the list of logged in users).
	sharedListNumber = 0;

	// Set the size of the list.  This value is only valid for this thread.
	//  Immediately after this thread is created, a user could have logged in
	//  changing the sizeOfLoggedInUsersList variable.
	// -TODO: Problem - if a user is logged in when this thread starts and logs out
	//   before the thread finishes iterating through the list...what happens?
	//     Possible solution:  Lock the list while copying it to a local variable.
	//       Doesn't sound too efficient, but it is one solution.
	curListSize = sizeOfLoggedInUsersList; 

	// Creating a pkt passing in the name of the user who sent the chat
	// UPDATE: use the following line when we update to use standalone chat server replacing the line below it.
//	myPkt = createPkt(in_pktId,"",from, sentFromClientName, "", chatData,0);
	myPkt = createPkt(1,"",from, sentFromClientName, "", chatData,0);

	// Checksum the pkt!
	// performing the checksum and assigning it to the pkt
	myPkt->_checksum = performChecksum(myPkt);

	/*                              */
	// start multi threaded section //
	/*                              */

	// Set the curPktNode pointer to the head of the list
	curPktNode = loggedInUsersList[sharedListNumber]._head;

	// Get the current listNumber variable as long as it is smaller than the list size
	//   The below while statemet will turn into an if statement for multithreaded version
	while(sharedListNumber < curListSize)
	{
		curListNumber = sharedListNumber;

		// Change myPkt port number to CLIENTCHATPORT (only needs to be done once)
		client.sin_port = htons(CLIENTCHATPORT);

		// Get the ip address from the list item and assign it to the client
		//   sockaddr_in struct variable
		client.sin_addr = ((struct pkt*)curPktNode->_data)->_client.sin_addr;

		// Get the family type from the list item and assign it to the client
		//   sockaddr_in struct variable
		client.sin_family = ((struct pkt*)curPktNode->_data)->_client.sin_family;

		if(rup_write(chatSock, myPkt, sizeof(struct pkt), &client) < 0)
		{
			if(errno == ENOBUFS)
				perror("Client Error: sending datagram");
			exit(1);
		}
		
		// Print the chat that was sent and who we sent it to.
		//printf("Sent chat: %s\n", ((struct pkt*)myPkt->_msgbuf));
		//printf("To: %s\n\n", ((struct pkt*)curPktNode->_data)->_client_name);

		// Increment the listNumber variable
		sharedListNumber++;

		// Check to see if there is a next item in the list by comparing the curListSize
		//  to the sharedListNumber which is being incremented.  If this comparison fails,
		//  there isn't another item in the list, so the pointer will not be incremented.
		if(sharedListNumber < curListSize)
		{
			curPktNode = curPktNode->_next;
		}
	}
	delete myPkt;

	/*                            */
	// end multi threaded section //
	/*                            */

}


/* chatServer
*
*  Description: Loop on a specified port number waiting for incoming chat
*                to process.
*  Input: void* tID - This is a placeholder parameter which is not used in the
*          function.  It is for the function call using threads
*  Output: void* - This is not used but is for the use of threads to return values.
*/
void* chatServer(void* tID)
{
//	int sock;
	int fromlen;
	struct sockaddr_in from;
	struct pkt inPkt;

	// Assign fromlen to the size of the sockaddr_in struct
	fromlen = sizeof(struct sockaddr_in);

	// Create INTERNET, udp datagram socket
	chatSock = rup_open();

	// Bind protocol to socket
	if(rup_bind(chatSock, SERVERCHATPORT)) 
	{
		exit(1); 
	}

	// Loop forever reading and writing on port
	for(;;)
	{
		int rc;

		memset(inPkt._msgbuf,0,BUFSIZE);

		if ((rc=rup_read(chatSock, &inPkt, sizeof(struct pkt), &from)) < 0 )
		{
			printf("chat server error: errno %d\n",errno);
			perror("reading datagram");
			exit(1);
		}

		// Send chat to everyone who is logged in
		//sendChatToList(chatSock, &from, inPkt._client_name, inPkt._msgbuf);
	}
	//rup_close(sock);  // FIXME: commented out because compiler warns it is unreachable code
}
